"""
剪映模板深度分析器

专门用于提取模板中的关键信息，包括设备信息和轨道素材信息
"""

import json
from pathlib import Path
from typing import Dict, List, Any, Optional, Tuple
from loguru import logger

from src.core.di import Service


@Service("jianying_template_analyzer")
class JianyingTemplateAnalyzer:
    """
    剪映模板深度分析器
    
    功能：
    1. 提取设备和应用信息
    2. 分析轨道结构，找出主要视频轨道
    3. 提取轨道上每个视频的详细信息
    """

    def __init__(self):
        self.logger = logger.bind(component="JianyingTemplateAnalyzer")

    def extract_device_info(self, draft_content: Dict[str, Any]) -> Dict[str, Any]:
        """
        提取设备和应用信息
        
        Args:
            draft_content: 草稿内容
            
        Returns:
            设备信息字典
        """
        device_info = {}
        
        # 从不同位置提取设备信息
        # 1. 从根级别提取
        for key in ["app_id", "app_source", "app_version", "device_id", "hard_disk_id", "mac_address", "os", "os_version"]:
            if key in draft_content:
                device_info[key] = draft_content[key]
        
        # 2. 从 platform 字段提取
        platform = draft_content.get("platform", {})
        if platform:
            for key in ["app_id", "app_source", "app_version", "device_id", "hard_disk_id", "mac_address", "os", "os_version"]:
                if key in platform:
                    device_info[key] = platform[key]
        
        # 3. 从 extra_info 或其他嵌套字段提取
        extra_info = draft_content.get("extra_info", {})
        if extra_info:
            for key in ["app_id", "app_source", "app_version", "device_id", "hard_disk_id", "mac_address", "os", "os_version"]:
                if key in extra_info:
                    device_info[key] = extra_info[key]
        
        self.logger.info(f"提取到设备信息: {len(device_info)} 个字段")
        return device_info

    def find_main_video_track(self, draft_content: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        找出主要的视频轨道（视频片段最多的轨道）
        
        Args:
            draft_content: 草稿内容
            
        Returns:
            主要视频轨道信息，如果没有找到返回None
        """
        tracks = draft_content.get("tracks", [])
        
        main_track = None
        max_video_segments = 0
        
        for i, track in enumerate(tracks):
            if track.get("type") != "video":
                continue
            
            segments = track.get("segments", [])
            video_segments = [s for s in segments if self._is_video_segment(s)]
            
            if len(video_segments) > max_video_segments:
                max_video_segments = len(video_segments)
                main_track = {
                    "track_index": i,
                    "track_id": track.get("id", ""),
                    "track_type": track.get("type", ""),
                    "video_segments_count": len(video_segments),
                    "total_segments_count": len(segments),
                    "track_data": track
                }
        
        if main_track:
            self.logger.info(f"找到主要视频轨道: 轨道{main_track['track_index']+1}, {main_track['video_segments_count']}个视频片段")
        else:
            self.logger.warning("未找到视频轨道")
        
        return main_track

    def _is_video_segment(self, segment: Dict[str, Any]) -> bool:
        """判断片段是否为视频片段"""
        # 检查多种可能的视频标识
        material_type = segment.get("material_type", "")
        if material_type == "video":
            return True
        
        # 检查是否有视频相关的属性
        if segment.get("has_video", False):
            return True
        
        # 检查素材ID是否指向视频素材
        material_id = segment.get("material_id", "")
        local_material_id = segment.get("local_material_id", "")
        
        if material_id or local_material_id:
            # 这里可以进一步检查素材库中的素材类型
            return True
        
        return False

    def extract_video_segments_info(self, main_track: Dict[str, Any], draft_content: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        提取主要视频轨道上每个视频片段的详细信息
        
        Args:
            main_track: 主要视频轨道信息
            draft_content: 草稿内容
            
        Returns:
            视频片段信息列表
        """
        if not main_track:
            return []
        
        track_data = main_track["track_data"]
        segments = track_data.get("segments", [])
        
        # 获取素材库信息用于查找素材详情
        materials = draft_content.get("materials", {})
        videos_materials = materials.get("videos", [])
        
        # 创建素材ID到素材信息的映射
        material_id_map = {}
        for video in videos_materials:
            vid = video.get("id", "")
            local_id = video.get("local_material_id", "")
            if vid:
                material_id_map[vid] = video
            if local_id:
                material_id_map[local_id] = video
        
        video_segments_info = []
        
        for i, segment in enumerate(segments):
            if not self._is_video_segment(segment):
                continue
            
            # 基本片段信息
            segment_info = {
                "segment_index": i,
                "segment_id": segment.get("id", ""),
                "material_id": segment.get("material_id", ""),
                "local_material_id": segment.get("local_material_id", ""),
                "material_name": segment.get("material_name", ""),
                "path": segment.get("path", ""),
            }
            
            # 时间信息
            target_timerange = segment.get("target_timerange", {})
            source_timerange = segment.get("source_timerange", {})
            
            segment_info.update({
                "target_start": target_timerange.get("start", 0) / 1000000,  # 转换为秒
                "target_duration": target_timerange.get("duration", 0) / 1000000,
                "source_start": source_timerange.get("start", 0) / 1000000,
                "source_duration": source_timerange.get("duration", 0) / 1000000,
            })
            
            # 计算结束时间
            segment_info["target_end"] = segment_info["target_start"] + segment_info["target_duration"]
            segment_info["source_end"] = segment_info["source_start"] + segment_info["source_duration"]
            
            # 从素材库中获取更多信息
            material_id = segment_info["material_id"] or segment_info["local_material_id"]
            if material_id in material_id_map:
                material_data = material_id_map[material_id]
                segment_info.update({
                    "material_width": material_data.get("width", 0),
                    "material_height": material_data.get("height", 0),
                    "material_duration": material_data.get("duration", 0) / 1000000,
                    "material_fps": material_data.get("fps", 0),
                    "material_has_audio": material_data.get("has_audio", False),
                    "material_file_path": material_data.get("path", ""),
                    "material_file_name": material_data.get("material_name", ""),
                })
            
            # 变换信息（位置、缩放、旋转等）
            transform = segment.get("common_keyframes", [])
            if transform:
                # 提取第一个关键帧的变换信息
                first_keyframe = transform[0] if transform else {}
                values = first_keyframe.get("values", [])
                if len(values) >= 6:  # 通常包含 x, y, z, scale_x, scale_y, rotation 等
                    segment_info.update({
                        "transform_x": values[0] if len(values) > 0 else 0,
                        "transform_y": values[1] if len(values) > 1 else 0,
                        "transform_scale_x": values[3] if len(values) > 3 else 1.0,
                        "transform_scale_y": values[4] if len(values) > 4 else 1.0,
                        "transform_rotation": values[5] if len(values) > 5 else 0,
                    })
            
            # 特效信息
            effects = segment.get("effects", [])
            segment_info["effects_count"] = len(effects)
            segment_info["effects"] = [effect.get("id", "") for effect in effects]
            
            video_segments_info.append(segment_info)
        
        self.logger.info(f"提取了 {len(video_segments_info)} 个视频片段的详细信息")
        return video_segments_info

    def analyze_template_structure(self, template_path: str) -> Dict[str, Any]:
        """
        分析模板结构，提取所有关键信息
        
        Args:
            template_path: 模板路径
            
        Returns:
            完整的模板分析结果
        """
        template_dir = Path(template_path)
        
        if not template_dir.exists():
            raise FileNotFoundError(f"模板路径不存在: {template_path}")
        
        # 读取草稿内容
        draft_content_file = template_dir / "draft_content.json"
        if not draft_content_file.exists():
            raise FileNotFoundError(f"draft_content.json 不存在: {draft_content_file}")
        
        try:
            with open(draft_content_file, 'r', encoding='utf-8') as f:
                draft_content = json.load(f)
        except Exception as e:
            raise ValueError(f"无法解析 draft_content.json: {e}")
        
        # 读取元信息
        draft_meta_info_file = template_dir / "draft_meta_info.json"
        draft_meta_info = {}
        if draft_meta_info_file.exists():
            try:
                with open(draft_meta_info_file, 'r', encoding='utf-8') as f:
                    draft_meta_info = json.load(f)
            except Exception as e:
                self.logger.warning(f"无法解析 draft_meta_info.json: {e}")

        # 提取设备信息
        device_info = self.extract_device_info(draft_content)

        # 找出主要视频轨道
        main_track = self.find_main_video_track(draft_content)

        # 提取视频片段信息
        video_segments = []
        if main_track:
            video_segments = self.extract_video_segments_info(main_track, draft_content)

        # 提取详细信息
        detailed_info = self._extract_detailed_info(draft_content, draft_meta_info)

        # 组合结果
        analysis_result = {
            "template_path": str(template_path),
            "template_id": template_dir.name,
            "template_name": draft_meta_info.get("draft_name", template_dir.name),
            "template_description": detailed_info["description"],
            "project_id": detailed_info["project_id"],
            "fps": detailed_info["fps"],
            "duration_seconds": detailed_info["duration_seconds"],
            "canvas_info": detailed_info["canvas"],
            "tracks_info": detailed_info["tracks"],
            "materials_info": detailed_info["materials"],
            "imported_materials_info": detailed_info["imported_materials"],
            "effects_info": detailed_info["effects"],
            "device_info": device_info,
            "main_video_track": main_track,
            "video_segments": video_segments,
            "analysis_summary": {
                "device_fields_count": len(device_info),
                "main_track_found": main_track is not None,
                "video_segments_count": len(video_segments),
                "total_video_duration": sum(seg.get("target_duration", 0) for seg in video_segments),
                "materials_count": len(detailed_info["materials"].get("videos", {}).get("details", [])) + len(detailed_info["materials"].get("audios", {}).get("details", [])),
            }
        }
        
        self.logger.info(f"模板分析完成: {analysis_result['analysis_summary']}")
        return analysis_result

    def _extract_detailed_info(self, draft_content: Dict[str, Any], draft_meta_info: Dict[str, Any]) -> Dict[str, Any]:
        """
        提取详细的模板信息

        Args:
            draft_content: 草稿内容
            draft_meta_info: 草稿元信息

        Returns:
            详细信息字典
        """
        info = {}

        # 基本信息
        info["project_id"] = draft_content.get("id", "")
        info["fps"] = draft_content.get("fps", 30.0)
        info["duration_seconds"] = draft_content.get("duration", 0) / 1000000

        # 画布配置
        canvas_config = draft_content.get("canvas_config", {})
        info["canvas"] = {
            "width": canvas_config.get("width", 0),
            "height": canvas_config.get("height", 0),
            "ratio": canvas_config.get("ratio", "unknown"),
            "aspect_ratio": self._calculate_aspect_ratio(canvas_config)
        }

        # 轨道分析
        tracks = draft_content.get("tracks", [])
        info["tracks"] = {
            "total": len(tracks),
            "video_tracks": len([t for t in tracks if t.get("type") == "video"]),
            "audio_tracks": len([t for t in tracks if t.get("type") == "audio"]),
            "details": self._analyze_tracks(tracks)
        }

        # 素材分析
        materials = draft_content.get("materials", {})
        info["materials"] = self._analyze_materials(materials)

        # 从元信息中提取素材详情
        meta_materials = draft_meta_info.get("draft_materials", [])
        info["imported_materials"] = self._analyze_meta_materials(meta_materials)

        # 特效和动画
        info["effects"] = {
            "video_effects": len(materials.get("effects", [])),
            "transitions": len(materials.get("transitions", [])),
            "animations": len(materials.get("material_animations", [])),
            "filters": len(materials.get("filters", [])),
            "stickers": len(materials.get("stickers", []))
        }

        # 生成描述
        info["description"] = self._generate_template_description(info)

        return info

    def _calculate_aspect_ratio(self, canvas_config: Dict[str, Any]) -> str:
        """计算宽高比"""
        width = canvas_config.get("width", 0)
        height = canvas_config.get("height", 0)

        if width and height:
            # 计算实际比例
            actual_ratio = width / height

            # 常见比例的识别（带容差）
            standard_ratios = [
                (16/9, "16:9"),
                (9/16, "9:16"),
                (4/3, "4:3"),
                (3/4, "3:4"),
                (1/1, "1:1"),
                (21/9, "21:9"),
                (3/2, "3:2"),
                (2/3, "2:3")
            ]

            # 使用容差匹配标准比例
            tolerance = 0.02  # 2% 容差
            for standard_ratio, ratio_name in standard_ratios:
                if abs(actual_ratio - standard_ratio) / standard_ratio < tolerance:
                    return ratio_name

            # 如果没有匹配的标准比例，计算最大公约数
            def gcd(a, b):
                while b:
                    a, b = b, a % b
                return a

            g = gcd(width, height)
            ratio_w = width // g
            ratio_h = height // g

            return f"{ratio_w}:{ratio_h}"

        return "unknown"

    def _analyze_tracks(self, tracks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """分析轨道详情"""
        track_details = []

        for i, track in enumerate(tracks):
            track_type = track.get("type", "unknown")
            segments = track.get("segments", [])

            track_info = {
                "index": i + 1,
                "type": track_type,
                "segments_count": len(segments),
                "total_duration": 0,
                "segments": []
            }

            for segment in segments:
                target_timerange = segment.get("target_timerange", {})
                duration = target_timerange.get("duration", 0) / 1000000
                start = target_timerange.get("start", 0) / 1000000

                track_info["total_duration"] += duration
                track_info["segments"].append({
                    "start": start,
                    "duration": duration,
                    "end": start + duration,
                    "material_id": segment.get("material_id", "")[:8] + "..."
                })

            track_details.append(track_info)

        return track_details

    def _analyze_materials(self, materials: Dict[str, Any]) -> Dict[str, Any]:
        """分析素材详情"""
        material_info = {}

        # 视频素材
        videos = materials.get("videos", [])
        material_info["videos"] = {
            "count": len(videos),
            "details": []
        }

        for video in videos[:5]:  # 只分析前5个
            material_info["videos"]["details"].append({
                "name": video.get("material_name", "unknown"),
                "duration": video.get("duration", 0) / 1000000,
                "width": video.get("width", 0),
                "height": video.get("height", 0),
                "has_audio": video.get("has_audio", False),
                "path": video.get("path", "")
            })

        # 音频素材
        audios = materials.get("audios", [])
        material_info["audios"] = {
            "count": len(audios),
            "details": []
        }

        for audio in audios[:3]:  # 只分析前3个
            material_info["audios"]["details"].append({
                "name": audio.get("name", "unknown"),
                "duration": audio.get("duration", 0) / 1000000,
                "path": audio.get("path", "")
            })

        # 其他素材类型
        material_info["texts"] = {"count": len(materials.get("texts", []))}
        material_info["images"] = {"count": len(materials.get("images", []))}
        material_info["stickers"] = {"count": len(materials.get("stickers", []))}

        return material_info

    def _analyze_meta_materials(self, meta_materials: List[Dict[str, Any]]) -> Dict[str, Any]:
        """分析元信息中的素材"""
        imported_info = {}

        type_names = {
            0: "videos",
            1: "audios",
            2: "images",
            3: "texts",
            6: "stickers",
            7: "effects",
            8: "others"
        }

        for material_group in meta_materials:
            material_type = material_group.get("type", -1)
            material_list = material_group.get("value", [])
            type_name = type_names.get(material_type, f"type_{material_type}")

            imported_info[type_name] = {
                "count": len(material_list),
                "details": []
            }

            # 详细分析视频素材
            if material_type == 0 and material_list:  # 视频
                for material in material_list[:3]:  # 只分析前3个
                    imported_info[type_name]["details"].append({
                        "name": material.get("extra_info", "unknown"),
                        "duration": material.get("duration", 0) / 1000000,
                        "width": material.get("width", 0),
                        "height": material.get("height", 0),
                        "path": material.get("file_Path", ""),
                        "id": material.get("id", "")
                    })

        return imported_info

    def _generate_template_description(self, info: Dict[str, Any]) -> str:
        """生成模板描述"""
        description_parts = []

        # 画布信息
        canvas = info.get("canvas", {})
        if canvas.get("ratio") != "unknown":
            description_parts.append(f"画布: {canvas['ratio']}")

        # 轨道信息
        tracks = info.get("tracks", {})
        if tracks.get("total", 0) > 0:
            track_desc = f"{tracks['total']}轨道"
            if tracks.get("video_tracks", 0) > 0:
                track_desc += f"({tracks['video_tracks']}视频"
                if tracks.get("audio_tracks", 0) > 0:
                    track_desc += f"+{tracks['audio_tracks']}音频)"
                else:
                    track_desc += ")"
            description_parts.append(track_desc)

        # 素材信息
        materials = info.get("materials", {})
        video_count = materials.get("videos", {}).get("count", 0)
        audio_count = materials.get("audios", {}).get("count", 0)

        if video_count > 0:
            description_parts.append(f"{video_count}个视频")
        if audio_count > 0:
            description_parts.append(f"{audio_count}个音频")

        # 特效信息
        effects = info.get("effects", {})
        effect_count = effects.get("video_effects", 0)
        transition_count = effects.get("transitions", 0)

        if effect_count > 0:
            description_parts.append(f"{effect_count}个特效")
        if transition_count > 0:
            description_parts.append(f"{transition_count}个转场")

        # 时长信息
        duration = info.get("duration_seconds", 0)
        if duration > 0:
            description_parts.append(f"{duration:.1f}秒")

        return " | ".join(description_parts) if description_parts else "剪映草稿项目模板"

    def extract_replacement_template(self, analysis_result: Dict[str, Any]) -> Dict[str, Any]:
        """
        提取用于素材替换的模板信息
        
        Args:
            analysis_result: 模板分析结果
            
        Returns:
            素材替换模板
        """
        if not analysis_result.get("main_video_track"):
            raise ValueError("没有找到主要视频轨道，无法创建替换模板")
        
        video_segments = analysis_result.get("video_segments", [])
        if not video_segments:
            raise ValueError("没有找到视频片段，无法创建替换模板")
        
        # 创建替换模板
        replacement_template = {
            "template_info": {
                "template_id": analysis_result["template_id"],
                "template_path": analysis_result["template_path"],
                "device_info": analysis_result["device_info"],
            },
            "track_info": {
                "track_index": analysis_result["main_video_track"]["track_index"],
                "track_id": analysis_result["main_video_track"]["track_id"],
                "video_segments_count": len(video_segments),
            },
            "segments_template": []
        }
        
        # 为每个视频片段创建替换模板
        for segment in video_segments:
            segment_template = {
                "segment_index": segment["segment_index"],
                "original_material_id": segment["material_id"],
                "original_local_material_id": segment["local_material_id"],
                "original_material_name": segment["material_name"],
                "original_path": segment["path"],
                "timing": {
                    "target_start": segment["target_start"],
                    "target_duration": segment["target_duration"],
                    "target_end": segment["target_end"],
                    "source_start": segment["source_start"],
                    "source_duration": segment["source_duration"],
                },
                "transform": {
                    "x": segment.get("transform_x", 0),
                    "y": segment.get("transform_y", 0),
                    "scale_x": segment.get("transform_scale_x", 1.0),
                    "scale_y": segment.get("transform_scale_y", 1.0),
                    "rotation": segment.get("transform_rotation", 0),
                },
                "material_properties": {
                    "width": segment.get("material_width", 0),
                    "height": segment.get("material_height", 0),
                    "duration": segment.get("material_duration", 0),
                    "fps": segment.get("material_fps", 30),
                    "has_audio": segment.get("material_has_audio", False),
                },
                "effects": segment.get("effects", []),
                # 这些字段将在替换时填入新的素材信息
                "new_material_id": None,
                "new_local_material_id": None,
                "new_material_name": None,
                "new_path": None,
            }
            
            replacement_template["segments_template"].append(segment_template)
        
        self.logger.info(f"创建替换模板: {len(replacement_template['segments_template'])} 个片段")
        return replacement_template
